package com.gzqylc.utils;

import okhttp3.*;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @Author YeFeng
 * @Date 2021 2021/4/27 下午12:52
 * @Version 1.0
 * http请求工具类
 * 增加了异常抛出，一般在链接不是的时候抛出，正确返回但是不是200只是警告，重试方法详情看下面
 * 加上注解之后，指定异常类型为
 * @See com.gzqylc.xj.biz.modules.common.mod.exception.ModException
 *
 *     /**
 *      @EnableRetry：此注解用于开启重试框架，可以修饰在SpringBoot启动类上面，也可以修饰在需要重试的类上
 *      proxyTargetClass：Boolean类型，用于指明代理方式【true：cglib代理，false：jdk动态代理】默认使用jdk动态代理
 *      @Retryable
 *      value：Class[]类型，用于指定需要重试的异常类型，
 *      include：Class[]类型，作用于value类似，区别尚未分析
 *      exclude：Class[]类型，指定不需要重试的异常类型
 *      maxAttemps：int类型，指定最多重试次数，默认3
 *      backoff：Backoff类型，指明补偿机制
 *      @BackOff
 *      delay:指定延迟后重试，默认为1000L,即1s后开始重试 ;
 *      multiplier:指定延迟的倍数
 *      @Recover
 *      当重试次数耗尽依然出现异常时，执行此异常对应的@Recover方法。
 *      异常类型需要与Recover方法参数类型保持一致，
 *      recover方法返回值需要与重试方法返回值保证一致
 *     public String recover(ModException e,int num) {
 *     }
 *      */

public class HttpUtils {

    private static final String HTTP_JSON = "application/json; charset=utf-8";
    private static final String HTTP_FORM = "application/x-www-form-urlencoded; charset=utf-8";

    private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
            .connectTimeout(40, TimeUnit.SECONDS)
            .readTimeout(40, TimeUnit.SECONDS)
            .writeTimeout(40, TimeUnit.SECONDS)
            .build();
    private static String execute(Request request) throws IOException {
        Response response = null;
        try {
            response = OK_HTTP_CLIENT.newCall(request).execute();
            if (response.code() == HttpStatus.OK.value()) {
                return response.body().string();
            }
        }finally {
            if (response != null){
                response.close();
            }
        }
        return null;
    }


    /**
     * get请求
     * @param url 带上http://
     * @return
     */
    public static String httpGet(String url) throws IOException {
        if (url == null || "".equals(url)) {
            return "";
        }

        Request.Builder builder = new Request.Builder();
        Request request = builder.get().url(url).build();
        return execute(request);
    }

    public static String httpGet(String url, Map<String, String> headers) throws IOException {
        if (CollectionUtils.isEmpty(headers)) {
            return httpGet(url);
        }

        Request.Builder builder = new Request.Builder();
        headers.forEach(builder::header);
        Request request = builder.get().url(url).build();
        return execute(request);
    }

    /**
     * 同步 POST调用 无Header
     *
     * @param url 带上http://
     * @param json json字符串
     * @return
     */
    public static String httpPostJson(String url, String json) throws IOException {
        if (url == null || "".equals(url)) {
            return "";
        }

        MediaType type = MediaType.parse(HTTP_JSON);
        RequestBody body = RequestBody.create(json,type);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        Request request = requestBuilder.post(body).build();
        return execute(request);
    }


    /**
     * 同步 POST调用 有Header
     *
     * @param url 带上http://
     * @param headers 请求头
     * @param json json字符串
     * @return
     */
    public static String httpPostJson(String url, Map<String, String> headers, String json) throws IOException {
        if (CollectionUtils.isEmpty(headers)) {
           return httpPostJson(url, json);
        }

        MediaType type = MediaType.parse(HTTP_JSON);
        RequestBody body = RequestBody.create(json,type);
        Request.Builder requestBuilder = new Request.Builder().url(url);
        headers.forEach(requestBuilder::addHeader);
        Request request = requestBuilder.post(body).build();
        return execute(request);
    }

    /**
     * 提交表单
     * @param url 带上http://
     * @param content 表单字符串
     * @param headers 请求头
     * @return
     */
    public static String postDataByForm(String url,  Map<String, String> headers, String content) throws IOException {
        MediaType type = MediaType.parse(HTTP_FORM);
        RequestBody body = RequestBody.create(content,type);

        Request.Builder requestBuilder = new Request.Builder().url(url);
        if (headers != null && headers.size() > 0) {
            headers.forEach(requestBuilder::addHeader);
        }
        Request request = requestBuilder
                .post(body)
                .build();

        return execute(request);
    }


    /**
     * GET请求
     */
    public static String doGet(String url,Map<String, String> header,Map<String, Object> param) throws IOException {

        if(param!=null){
            url=getUrl(url,param);
        }
        final Request.Builder builder=new Request.Builder();
        if(header!=null){
            for(String key:header.keySet()){
                builder.addHeader(key,header.get(key));
            }
        }
        Request request=builder.url(url).get().build();
        return execute(request);

    }

    /**
     * 发送POST请求
     */
    public static String doPost(String url,Map<String, String> header,Map<String, Object> param) throws IOException {
        final Request.Builder builder=new Request.Builder();
        final FormBody.Builder bodyBuilder = new FormBody.Builder();

        if(header!=null){
            for(String key:header.keySet()){
                builder.addHeader(key,header.get(key));
            }
        }
        if(param!=null){
            for(String key:param.keySet()){
                bodyBuilder.add(key,param.get(key).toString());
            }
        }
        Request request=builder.url(url).post(bodyBuilder.build()).build();

        return execute(request);


    }


    public static String getUrl(String url, Map<String, Object> param) {
        if (param.size() > 0) {
            StringBuilder stringBuilder = new StringBuilder(url);
            stringBuilder.append("?");
            Set<Map.Entry<String, Object>> entries = param.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                stringBuilder.append(entry.getKey() + "=" + entry.getValue() + "&");
            }
            url = stringBuilder.substring(0, stringBuilder.length() - 1);
        }
        return url;
    }



    public static String postDataByArray(String url,  Map<String, String> headers, byte[] content) throws IOException {
        MediaType type = MediaType.parse(HTTP_JSON);
        RequestBody body = RequestBody.create(content,type);

        Request.Builder requestBuilder = new Request.Builder().url(url);
        if (headers != null && headers.size() > 0) {
            headers.forEach(requestBuilder::addHeader);
        }
        Request request = requestBuilder
                .post(body)
                .build();
        return execute(request);
    }

}
